/* SchedulerD.java
 * 
 * Alex Schwartz
 * Derek Dupuis
 * Greg Warner
 * Mike Dixey
 * 
 * Last level scheduler, moves the day of the tour
 * one forward and back by increasing days off the 
 * start date until tour is scheduleable
 * (gives the closest day to the proposed start 
 * date of the tour possible)
 * 
 */

import java.util.*;
import java.text.*;

public class SchedulerA implements ScheduleIF
{
   public boolean schedule( TourApp tA, TourOff tO )
   {
      EventColl events = tO.tour().events();
      
      Event e;
      GregorianCalendar start, end;
      int days;
      boolean forward = true;
      //must check all events for conflict
      for( days = 1; true; days++ )
      {
         forward = true;
         for( int i = 0; i < events.size(); i++ )
         {
            e = events.get( i );
            
            //calculate start and end time of event
            start = (GregorianCalendar)tO.startDate().clone();
            end = (GregorianCalendar)tO.startDate().clone();
            start.add( Calendar.DAY_OF_MONTH, 
                      e.startTime().get( Calendar.DAY_OF_MONTH ) - 1 + days);
            start.add( Calendar.HOUR_OF_DAY,
                      e.startTime().get( Calendar.HOUR_OF_DAY ) );
            start.add( Calendar.MINUTE,
                      e.startTime().get( Calendar.MINUTE ) );
            
            end.add( Calendar.DAY_OF_MONTH, 
                    e.endTime().get( Calendar.DAY_OF_MONTH ) - 1 + days );
            end.add( Calendar.HOUR_OF_DAY,
                    e.endTime().get( Calendar.HOUR_OF_DAY ) );
            end.add( Calendar.MINUTE,
                    e.endTime().get( Calendar.MINUTE ) );
            //check if event works with provider
            Provider p = e.provider();
            if( p.service().type().compareTo( "lodging" ) == 0 )
            {
               if( p.conflict( tO.roomsNeeded(), start, end ) )
                  break;
            }
            else if( p.conflict( tO.size(), start, end ) )
               break;
            
            if( i + 1 == events.size() )
            {
               makeBookings(tO,events,days,forward);
               return true;
            }
         }
         
         forward = false;
         for( int i = 0; i < events.size(); i++ )
         {
            
            e = events.get( i );
            
            //calculate start and end time of event
            start = (GregorianCalendar)tO.startDate().clone();
            end = (GregorianCalendar)tO.startDate().clone();
            start.add( Calendar.DAY_OF_MONTH, 
                      e.startTime().get( Calendar.DAY_OF_MONTH ) - 1 - days);
            start.add( Calendar.HOUR_OF_DAY,
                      e.startTime().get( Calendar.HOUR_OF_DAY ) );
            start.add( Calendar.MINUTE,
                      e.startTime().get( Calendar.MINUTE ) );
            
            end.add( Calendar.DAY_OF_MONTH, 
                    e.endTime().get( Calendar.DAY_OF_MONTH ) - 1 - days );
            end.add( Calendar.HOUR_OF_DAY,
                    e.endTime().get( Calendar.HOUR_OF_DAY ) );
            end.add( Calendar.MINUTE,
                    e.endTime().get( Calendar.MINUTE ) );
            //check if event works with provider
            Provider p = e.provider();
            if( p.service().type().compareTo( "lodging" ) == 0 )
            {
               if( p.conflict( tO.roomsNeeded(), start, end ) )
                  break;
            }
            else if( p.conflict( tO.size(), start, end ) )
               break;
            if( i + 1 == events.size() )
            {
               makeBookings(tO,events,days,forward);
               return true;
            }
         }
         
      }
   }
   
   void makeBookings( TourOff tO, EventColl events, int days, boolean forward )
   {
      //if it gets here, no conflict detected schedule all events
      System.out.printf( "Offering: %s was moved %d day(s) ", tO.offeringName(), days );
      System.out.printf( "%s.", forward ? "later" : "earlier" );
      for( int i = 0; i < events.size(); i++ )
      {
         Event e = events.get( i );
         
         //calculate start and end time of event
         GregorianCalendar start = (GregorianCalendar)tO.startDate().clone();
         GregorianCalendar end = (GregorianCalendar)tO.startDate().clone();
         if( forward )
         {
            start.add( Calendar.DAY_OF_MONTH, 
                      e.startTime().get( Calendar.DAY_OF_MONTH ) - 1 + days );
         }
         else
         {
            start.add( Calendar.DAY_OF_MONTH, 
                      e.startTime().get( Calendar.DAY_OF_MONTH ) - 1 - days );
         }
         start.add( Calendar.HOUR_OF_DAY,
                   e.startTime().get( Calendar.HOUR_OF_DAY ) );
         start.add( Calendar.MINUTE,
                   e.startTime().get( Calendar.MINUTE ) );
         
         if( forward )
         {
            end.add( Calendar.DAY_OF_MONTH, 
                    e.startTime().get( Calendar.DAY_OF_MONTH ) - 1 + days );
         }
         else
         {
            end.add( Calendar.DAY_OF_MONTH, 
                    e.startTime().get( Calendar.DAY_OF_MONTH ) - 1 - days );
         }
         end.add( Calendar.HOUR_OF_DAY,
                 e.endTime().get( Calendar.HOUR_OF_DAY ) );
         end.add( Calendar.MINUTE,
                 e.endTime().get( Calendar.MINUTE ) );
         
         //schedule event
         Provider p = e.provider();
         if( p.service().type().compareTo( "lodging" ) == 0 )
            p.addBooking( new Booking( tO.roomsNeeded()
                                         , start, end ) );
         else 
            p.addBooking( new Booking( tO.size(),
                                      start, end ) );
         
      }
   }
}